#pragma once 
// server 和 client都包含这个文件，就看到了同一份协议
#include "protocol.hpp"
#include <pthread.h>
namespace ns_server {
    class Server {
        private:
            uint16_t port;
            int listen_sock;
        public:
            Server(uint16_t _port)
                :port(_port)
                ,listen_sock(0)
            {}
            void initServer() {
                listen_sock = socket(AF_INET, SOCK_STREAM, 0);
                if (listen_sock < 0) {
                    std::cerr << "socket fail " << std::endl;
                    exit(1);
                }
                struct sockaddr_in local;
                bzero(&local, sizeof(local));
                local.sin_family = AF_INET;
                local.sin_port = htons(port);
                local.sin_addr.s_addr = htonl(INADDR_ANY);
                if (bind(listen_sock, (struct sockaddr*)&local, sizeof(local))) {
                    std::cerr << "bind error " << std::endl;
                    exit(2);
                }
                if (listen(listen_sock, 5) < 0) {
                    std::cerr << "listen error " << std::endl;
                    exit(3);
                }
            }  

            static void* cal(void *args) {
                int sock = *(int *)args;
                delete (int*)args;
                while (true) {
                    ns_protocol::request req;
                    // recv 等价于 read；但是不等于recvfrom
                    ssize_t s = recv(sock, &req, sizeof(req), 0);
                    // 反序列化
                    if (s > 0) {
                        ns_protocol::response resp;
                        switch(req.op) {
                            case '+':
                                resp.result = req.x + req.y;
                                resp.code = 0;
                                break;
                            case '-':
                                resp.result = req.x - req.y;
                                resp.code = 0;
                                break;
                            case '*':
                                resp.result = req.x * req.y;
                                resp.code = 0;
                                break;
                            case '/':
                                if (req.y == 0) {
                                    resp.code = 1;
                                } else {
                                    resp.result = req.x / req.y;
                                    resp.code = 0;
                                }
                                break;
                            case '%':
                                if (req.y == 0) {
                                    resp.code = 2;
                                } else {
                                    resp.result = req.x % req.y;
                                    resp.code = 0;
                                }
                                break;
                            default:
                                break;
                        }
                        // 需要一个序列化过程
                        // send 等价于 write，但是不等价于 sendto
                        send(sock, &resp, sizeof(resp), 0);
                    } else if (s == 0) {
                        std::cout << "client quit, me too  " << std::endl;
                        break;
                    } else {
                        std::cerr << "client error, server will quit " << std::endl;
                        break;
                    }
                }
                close(sock);
                return nullptr;
            }

            void Loop() {
                while (true) {
                    struct sockaddr_in peer;
                    socklen_t len = sizeof(peer);
                    int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
                    if (sock < 0) {
                        std::cerr << "accept error " << std::endl;
                        exit(4);
                    }
                    // handler
                    pthread_t tid;
                    int *p = new int(sock);
                    pthread_create(&tid, nullptr, cal, p);
                }
            }
            ~Server() {
                if (listen_sock >= 0) {
                    close(listen_sock);
                }
            }

    };
}


